package org.NooLab.tikaserver;

import java.util.Observable;
import java.util.Observer;

import org.NooLab.structures.ArgumentsPublicIntf;
import org.NooLab.tikaserver.tcp.agents.TikaServerAgent;
import org.NooLab.utilities.files.DFutils;
import org.NooLab.utilities.files.PathFinder;
import org.NooLab.utilities.files.StopFileWatcher;
import org.NooLab.utilities.logging.LogControl;
import org.NooLab.utilities.logging.PrintLog;
import org.NooLab.utilities.strings.StringsUtil;
import org.apache.commons.collections.BidiMap;
import org.apache.commons.collections.bidimap.DualHashBidiMap;

import com.cybozu.labs.langdetect.DetectorFactory;




@SuppressWarnings("rawtypes")
public class TikaServerFactory implements Observer{

	TikaServerAgent server;
	TikaQueue tikaQueue;
	
	ArgumentsPublicIntf arguments ;
	
	private Integer resultType=0;
	String appSecret="", homedir ="";
	
	int[] ports = new int[2] ;
	int listenPort=0, returnPort=0;
	
	
	BidiMap languageMap = new DualHashBidiMap();
	
	PrintLog out = new PrintLog(2,true);
	private StopFileWatcher stopper;
	
	
	// ========================================================================
	public TikaServerFactory( int listenport, int returnport) {

		LogControl.Level = 2 ;
		out.setPrefix("[tikasrv]");
		
		listenPort = listenport ;  
		returnPort = returnport;
		server = new TikaServerAgent( this, returnPort,listenPort );
	}
	
	public TikaServerFactory(ArgumentsPublicIntf arguments) {
		
		out.setPrefix("[tikasrv]");
		
		this.arguments = arguments;
		
		assimilateArguments(arguments);
		
		server = new TikaServerAgent( this, returnPort,listenPort );
	}
	// ========================================================================

	public void close(){
		
		stopper.close();
		server.close();
	}
	
	
	public void start() throws Exception {
	 
		
		// the tika queue stuff
		
		tikaQueue = new TikaQueue( this ) ;	
		tikaQueue.start();
		
		
		String path , profileDirectory;
		
		path = homedir;
		path = (String) arguments.getMappedTopic("homedir") ;
		if (path==null){
			path = ""; // ???
		}
		if (DFutils.folderExists(path)==false){
			
		}
		path = DFutils.createPath(path, "/") ;
		
		profileDirectory = DFutils.getParentDir(homedir, 2);
		profileDirectory = DFutils.createPath(profileDirectory ,"common/profiles/");
		String filename = DFutils.createPath(profileDirectory ,"en");
		
		// 
											
		if (DFutils.fileExists(filename)){
											out.print(2, "loading language detection...");
			DetectorFactory.loadProfile(profileDirectory);
											out.print(2, "loading language detection done.");
		}else{
			out.printErr(2, "Potential Problem: language detection is not available!");
		}
		
		
		String sfile ;
		sfile = (new PathFinder()).getAppBinPath(this.getClass(), true);
		if (sfile.indexOf(".jar")>0){
			sfile = StringsUtil.getLastPartOfString( sfile, "/") ;
		}else{
			sfile = PathFinder.getMainClassName() ; // this does not work: System.getenv("JAVA_MAIN_CLASS");
			if(sfile.length()==0){
				sfile = "NooLabTikaServer.jar";
			}
		}
		String ext = StringsUtil.getExtensionFromFilename(sfile);
		sfile = sfile.replace(ext, "")+".stop";
		
		stopper = new StopFileWatcher( (Observer)this, path, sfile, false, 500);
		
		out.print(2, "StopFileWatcher is observing file <"+stopper.getObservedFile()+">");
		
		int z=0; 
		while ((z<500) && (stopper.isObserving()==false)){
			out.delay(2);	z++;
		}
		if (stopper.isObserving()==false){
			out.print(1, "No stop file observer available!");
		}
		
		// and the tcp
		server.start();
		if (server.receiverIsNull()){
			tikaQueue.stop();
			PrintLog.Delay(500);
			out.print(1, "TikaServer failed to start properly, stopping...");
			System.exit(-4) ;
		}
		out.print(2, "TikaServer has been started successfully (id:"+appSecret+"), \n"+
					 "          listening on port <"+listenPort+"> ...");
		out.delay(50);

	}

	// this returns from TikaQueue = the text extracting procedure, or from StopFileWatcher
	@Override
	public void update(Observable sendObj, Object msgObj) {
	
		String senderName = sendObj.getClass().getSimpleName();
		// we send it back 
		out.print(1, "msg from <"+(sendObj.getClass().getSimpleName())+">");
		out.print(1, " ... received by TikaServer : "+((String) msgObj)) ;
		if ((senderName.contains("StopFile")) && ((String) msgObj).contains("StopFile")){
			close();
			out.delay(300);
			out.printErr(2, "TikaServer has been shut down.\n");
			System.exit(1);
		}
			
		
	}

	// ========================================================================
	
	
	
	public void assimilateArguments(ArgumentsPublicIntf arguments){
	
		int olev = -1;
		
		if (arguments==null){
			return;
		}
		ports = arguments.getPorts() ;
				
		
		returnPort = ports[1] ;
		listenPort = ports[0] ;
	
		if ((arguments.count()>0) && (arguments.contains("loglevel"))){
			olev = (Integer)arguments.getMappedTopic("loglevel") ;
		}
		if ((olev>=1) && (olev<=5)){
			LogControl.Level = olev;
		}
		
		appSecret = arguments.getAppSecret() ;
		
		homedir = (String) arguments.getMappedTopic("homeDir");
		
		resultType = (Integer) arguments.getMappedTopic("result");
	}

	public void setAppSecret(String appsecret) {
		// 
		appSecret = appsecret;
	}

	public Integer getResultType() {
		return resultType;
	}
	

	public void createLanguageMap(){

		/*  should be compliant to ISO-3166-Alpha-2
		af	Afrikaans
		ar	Arabic
		bg	Bulgarian
		bn	Bengali
		cs	Czech
		da	Dannish
		de	German
		el	Greek
		en	English
		es	Spanish
		et	Estonian
		fa	Persian
		fi	Finnish
		fr	French
		gu	Gujarati
		he	Hebrew
		hi	Hindi
		hr	Croatian     
		hu	Hungarian
		id	Indonesian
		it	Italian
		ja	Japanese
		kn	Kannada       
		ko	Korean
		lt	Lithuanian
		lv	Latvian
		mk	Macedonian
		ml	Malayalam
		mr	Marathi
		ne	Nepali
		nl	Dutch
		no	Norwegian
		pa	Punjabi
		pl	Polish
		pt	Portuguese
		ro	Romanian
		ru	Russian
		sk	Slovak
		sl	Slovene
		so	Somali
		sq	Albanian
		sv	Swedish   
		sw	Swahili   
		ta	Tamil  
		te	Telugu
		th	Thai
		tl	Tagalog
		tr	Turkish
		uk	Ukrainian
		ur	Urdu
		vi	Vietnamese
		zh-cn	Simplified Chinese
		zh-tw	Traditional Chinese
		*/
		languageMap.put("sv", new String[]{"se","Swedish"});
		languageMap.put("sw", new String[]{"su","Suaheli"});
		
	}

	public String getISO3166Code(String inCode) {
		String languageCode="" ;
		
		if (languageMap.containsKey(inCode)){
			Object obj = languageMap.get(inCode);
			languageCode = ((String[])obj)[0];
		}else{
			languageCode = inCode ;
		}
		
		return languageCode;
	}

}
